﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

using COUP.Game.Networking;
using COUP.Core.Networking;
using COUP.Core.Database;
using COUP.Core.Entities;
using COUP.Core.Files;
using COUP.Core.Forms;
using COUP.Core;

namespace COUP.Game
{
    unsafe static class Program
    {
        public static iDatabase Database;
        public static Dictionary<int, Map> Maps;
        public static Dictionary<uint, ItemTypeEntry> ItemData = new Dictionary<uint, ItemTypeEntry>();
        public static Dictionary<uint, MagicTypeEntry> MagicData = new Dictionary<uint, MagicTypeEntry>();
        public static Dictionary<string, MonsterTypeEntry> MonsterData = new Dictionary<string, MonsterTypeEntry>();
        public static ConnectionHandler Connection;
        public static MapView mapView;
        public static int ServerID, Version;

        private static Log ConsoleLog = new Log("GameOutput");

        public static void Output(string Output, string Header = "Game Server")
        {
            Monitor.Enter(Console.Out);
            ConsoleLog.WriteLine("[" + Header + "] " + Output);
            Console.WriteLine("[{0}] {1}", Header, Output);
            Monitor.Exit(Console.Out);
        }

        static void Main(string[] StartArgs)
        {
            //Retreives the Title, Version and ServerID from the command line switches
            //These should be seperated by spaces.
            Title(StartArgs[0]);
            Version = int.Parse(StartArgs[2]);
            ServerID = ushort.Parse(StartArgs[3]);

            //Creates the main server socket and connection handler based on the port which
            //is also send via command line switch.
            Connection = new ConnectionHandler(int.Parse(StartArgs[1]));

            //Configures the server.
            Configure();

            //Allows the creation of test conditions.
            Test();

            //Allows people to connect to the server.
            Connection.AllowConnections = true;

            //Informs console and log of online status and allows user input via the console.
            Output("Server is Online");
            Input();
        }

        static void Configure()
        {
            //General configuration, place things that are generic to all your servers here
            //such as assigning your database, loading data from flat files where required.
            Database = new MsSqlDatabase();
            Maps = GameMap.Parse();
            ItemData = ItemType.Parse();
            MagicData = MagicType.Parse();
            MonsterData = MonsterType.Parse();

            //Version specific configuration, it is crucial that this configuration occurs
            //before you begin accepting connections to your server, within this switch you
            //must set the handler which will deal with all incoming packets, if you dont
            //the server will not function.
            switch (Version)
            {
                case 4267:
                    Connection.Handle += new PacketEventHandler(PacketHandler_4267.Handle_Packet); break;
                default:
                    throw new NotImplementedException("The Version you have specified is not implemented at this time.");
            }            
        }

        static void Test()
        {
            //The test method currently spawns 10k pheasants in twin city as part of my
            //on going debugging of the quadtree, spawning and monster systems. I aim
            //to implement a multi-threaded spawning system which will allow a massive 
            //amount of monsters to be spawned in a very short period of time, this
            //single-threaded method takes quite a while to spawn 100k, as a result i
            //reduced the number to 10k because it was taking too long to complete.

            Maps[1002].Insert(new Spawn(MonsterData["Pheasant"], Maps[1002], new System.Drawing.Point(450, 350), new System.Drawing.Size(20, 20), 20));

            return;

            Random Rand = new Random(Environment.TickCount);

            for (int x = 0; x < 10000; x++)
            {
                int X = Rand.Next(970);
                int Y = Rand.Next(970);

                while (!Maps[1002].CheckMove(new System.Drawing.Point(X, Y)))
                {
                    X = Rand.Next(970);
                    Y = Rand.Next(970);
                }
                
                Monster Pheasant = new Monster(x, X, Y);
                Maps[1002].Insert(Pheasant);
            }
        }

        static void Title(string Title)
        {
            //Changes the console's title to something more relevant.
            Console.Title = Title + " Server";
        }

        static void Input()
        {
            //Main thread currently ends up here performing input handling.
            while (true)
            {
                //Reads the next line when it becomes available.
                string com = Console.ReadLine().ToLower();

                //This switch contains all console based commands.
                switch (com)
                {
                        //Closes the Server unsafely.
                    case "exit": return;
                        //Loads the Mapview GUI, currently this is a "One Shot" command, loading
                        //it a second time even after closing the form will cause a fatal exception.
                    case "map":
                        {
                            Thread mapThread = new Thread(new ThreadStart(MapViewStart));
                            mapThread.Start();
                            Thread mapUpdate = new Thread(new ThreadStart(MapViewUpdate));
                            mapUpdate.Start();
                            continue;
                        }
                }
            }
        }

        static void MapViewStart()
        {
            //Creates the MapView Form and displays it.
            mapView = new MapView(Maps);
            mapView.Show();

            while (true)
            {
                Application.DoEvents();      
            }
        }

        static void MapViewUpdate()
        {
            //Waits for the object to be created.
            while (mapView == null) { }
            //Updates the MapView form every 250ms so that the image of the map
            //accurately reflects the changes on the map in pseudo real-time.
            while (mapView.Display)
            {
                mapView.Invalidate(true);
                Thread.Sleep(mapView.RefreshRate);
            }
        }
    }
}
